#include <windows.h>

#include "resource.h" 
#include "proiect.h" 
int* v,ifisier;
double timp_inserare,timp_cautare_min;
int verify_add(int val,int i)
{
	for(int j=0;j<i;j++)
	{
		if(val==v[j])
			return 0;
	}
	return 1;
}
int verificare_intregi(char* nume)
{
	FILE *f=fopen(nume,"r");
	char c;
	while (fscanf(f,"%c",&c)!=EOF)
	{
		if(isdigit(c)|| c==' '|| c=='\n');
		else
		{
			fclose(f);
			return 0;
		}
	}
	fclose(f);
	return 1;
}//verificarea fisierului(sa contina doar nr intregi)
int inserare_fisier( char* nume)
{
	FILE *f=fopen(nume,"r");
	if(f==NULL)
		return 0;
	else
	{
		if(verificare_intregi(nume))
		{
			int b;
			while(fscanf(f,"%d",&b)!=EOF)
			{
				if(verify_add(b,ifisier))
				{
					v=(int*)realloc(v,(ifisier+1)*sizeof(int));
					v[ifisier]=b;
					ifisier++;
				}
			}
		}
	}
	fclose(f);
	return 1;
}//inserarea nr din fisier intr un vector
//pentru cronometrare
double PCFreq = 0.0;
__int64 CounterStart = 0;

void StartCounter()
{
    LARGE_INTEGER li;
    if(!QueryPerformanceFrequency(&li))
		printf("QuerryPerformance Failrd");
    PCFreq = double(li.QuadPart)/1000000000.0;

    QueryPerformanceCounter(&li);
    CounterStart = li.QuadPart;
}
double GetCounter()
{
    LARGE_INTEGER li;
    QueryPerformanceCounter(&li);
    return double(li.QuadPart-CounterStart)/PCFreq;
}


NODE* root[100],*root1;
int nr_root=0;
int curr_heap;
HDC hdc;
HWND hwnd;
HINSTANCE hInst;
int nod_minim;

typedef struct stack
{
	NODE *nod;
	int level_y;
	int x_coordonate;
	int y_coordonate;
	stack *next;
	bool ok;
}stack;
stack *head;

void push_stack(NODE *nod,int level,int x,int y,bool ok)
{
	stack *nou=(stack *)malloc(sizeof(stack));
	nou->nod=nod;
	nou->level_y=level;
	nou->x_coordonate=x;
	nou->y_coordonate=y;
	nou->next=head;
	nou->ok=ok;

		head=nou;
}
NODE *poop()
{
	if(head==NULL)
		return NULL;

	stack *nod=head;
	head=head->next;

	NODE *node2=nod->nod;
	free(nod);
	return node2;
}

void reset_grafic()//pentru reprezentarea nodurilor
{
	PAINTSTRUCT Ps;
	hdc=BeginPaint(hwnd, &Ps);
	hdc=GetDC(hwnd);

	HBRUSH hBrush= CreateSolidBrush(RGB(255,255,255));
	HPEN pen;
	pen = CreatePen(PS_SOLID,2,RGB(255,255,255));
	SelectObject(hdc,pen);
	SelectObject(hdc,hBrush);
	Rectangle(hdc,0,0,1500,1000);
	DeleteObject(pen);
	DeleteObject(hBrush);

	EndPaint(hwnd, &Ps);
}
void display(NODE *root)//la fel
{
	reset_grafic();
	if(root==NULL)
		return;

	PAINTSTRUCT Ps;
	hdc=BeginPaint(hwnd, &Ps);

	HPEN pen;
	hdc=GetDC(hwnd);

//	Ellipse(hdc, 1300, 20, 1350, 70);
	if( root->sibling && (root->sibling->degree+1)==root->degree )
		push_stack(root,0,0,0,1);
	else
		push_stack(root,0,0,0,0);

	int level_x=0, level_y=0;
	int coordonata_x,coordonata_y;

	stack *temp=head;

	while(temp!=NULL)
	{
		NODE *temp2=temp->nod;
		level_y=temp->level_y;
		coordonata_x = 1300 - level_x*40;
		coordonata_y = 20 + 60*(level_y);
			if(temp->nod != root && temp->ok)
			{
				pen = CreatePen(PS_SOLID,2,RGB(0,255,0));
				SelectObject(hdc,pen);

				MoveToEx(hdc,coordonata_x + 15, coordonata_y, NULL);
				LineTo( hdc, temp->x_coordonate, temp->y_coordonate );

				DeleteObject(pen);
			}
		int i=0;
		poop();
		while(temp2!=NULL)
		{
			pen = CreatePen(PS_SOLID,2,RGB(0,0,0));
			SelectObject(hdc,pen);

			coordonata_x = 1300 - level_x*40;
			coordonata_y = 20 + 60*(level_y + i );
			Ellipse(hdc, coordonata_x, coordonata_y, coordonata_x + 30, coordonata_y + 30);

			char c[7];
			itoa(temp2->info, c, 10);
			TextOut(hdc, coordonata_x + 6, coordonata_y + 8, c, strlen(c));

			if(temp2->child)
			{
				MoveToEx(hdc, coordonata_x + 15, coordonata_y + 30, NULL);
				LineTo(hdc, coordonata_x + 15, coordonata_y + 60);
			}
			if(temp2->sibling )
				if(temp2->sibling->degree == ( temp2->degree - 1 ) )
					push_stack(temp2->sibling, level_y + i +1 , coordonata_x, coordonata_y + 15,1);
				else
					push_stack(temp2->sibling, level_y + i +1 , coordonata_x, coordonata_y + 15,0);

			temp2=temp2->child;
			i++;
			DeleteObject(pen);
		}

		
		temp=head;
		
		level_x++;
	}
	head=NULL;
	EndPaint(hwnd, &Ps);
	//
	//MoveToEx(hdc,1300,20, NULL);
	//LineTo(hdc,1350,70);

	//DeleteObject(pen);
}
void display_grafic_timp(double timp_inserare,double timp_cautare, int nod_min)//pentru grafice
{
	reset_grafic();

	PAINTSTRUCT Ps;
	hdc=BeginPaint(hwnd, &Ps);
	hdc=GetDC(hwnd);
	HPEN hPen = CreatePen(PS_SOLID,3,RGB(0,0,0));
	HBRUSH bBrush = CreateSolidBrush(RGB(100,220,200));

	SelectObject(hdc,hPen);
	SelectObject(hdc, bBrush);

		char q[1000];

			sprintf(q,"%f ",timp_inserare);
			strcat(q," milisec.");
			TextOut(hdc,140,660,q,strlen(q));		// timpul inserarii
			sprintf(q, "Timp inserare");
			TextOut(hdc,130,70,q,strlen(q));

			sprintf(q,"%f ",timp_cautare);
			strcat(q," milisec.");
			TextOut(hdc,470,660,q,strlen(q));
			sprintf(q, "Timp cautare",nod_min);
			TextOut(hdc,465,70,q,strlen(q));

			sprintf(q,"Nodul minim este %d ,  iar cronometrarea s-a efectuat pe %d elemente ",nod_min,ifisier);
			TextOut(hdc,60,30,q,strlen(q));

		double high;		
		if(timp_inserare > timp_cautare)		
		{
			hPen = CreatePen(PS_SOLID,3,RGB(0,0,0));
		    bBrush = CreateSolidBrush(RGB(255,0,0));
			SelectObject(hdc,hPen);
			SelectObject(hdc, bBrush);
			Rectangle(hdc,140,600,190,105);

			hPen = CreatePen(PS_SOLID,3,RGB(0,0,0));
		    bBrush = CreateSolidBrush(RGB(0,0,255));
			SelectObject(hdc,hPen);
			SelectObject(hdc, bBrush);
			high=(timp_cautare*495)/timp_inserare;		
			Rectangle(hdc,470,600,520,600 - high);
		}
		else		
		{
			hPen = CreatePen(PS_SOLID,3,RGB(0,0,0));
		    bBrush = CreateSolidBrush(RGB(255,0,0));
			SelectObject(hdc,hPen);
			SelectObject(hdc, bBrush);
			Rectangle(hdc,470,600,520,105);

			hPen = CreatePen(PS_SOLID,3,RGB(0,0,0));
		    bBrush = CreateSolidBrush(RGB(0,0,255));
			SelectObject(hdc,hPen);
			SelectObject(hdc, bBrush);
			high=(timp_inserare*495)/timp_cautare;		
			Rectangle(hdc,140,600,190,600 - high);
		}
	DeleteObject(hPen);
	DeleteObject(bBrush);

	EndPaint(hwnd, &Ps);
}

BOOL CALLBACK DlgProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam)
{
				
	switch(Message)
	{

		case WM_INITDIALOG:
			// This is where we set up the dialog box, and initialise any default values

			SetDlgItemText(hwnd, IDC_TEXT, "Insert a value");
			
			root[nr_root] = CREATE_BHEAP();
				SendDlgItemMessage(hwnd, IDC_LIST, LB_RESETCONTENT, 0, 0);
					curr_heap=nr_root;
					nr_root++;
					SetDlgItemInt(hwnd, IDC_SHOWCOUNT2 , curr_heap,FALSE);
					SetDlgItemInt(hwnd, IDC_SHOWCOUNT , nr_root,FALSE);
		//	SetDlgItemInt(hwnd, IDC_SHOWCOUNT , 0,FALSE);
			
		break;
		
		case WM_COMMAND:
			
			switch(LOWORD(wParam))
			{
			case IDC_BUTTON1:///pentru introducerea din fisier
				{
					
						int wmId, wmEvent,i=0;
						PAINTSTRUCT ps;
						HDC hdc,hdc2;
						LPCSTR Y;
						HICON hicon, hicon_sm;
						HWND d1=NULL, d2=NULL, d3=NULL;
   					  HDC hDC;
						OPENFILENAME fon;
						char szFileName[MAX_PATH] = "";
						HPEN bluePen; 
						HGDIOBJ oldPen;
						HFONT font;
						hdc=GetDC(hwnd);
						ZeroMemory(&fon,sizeof(fon));
						fon.lStructSize = sizeof(fon);
						fon.hwndOwner = hwnd;
						fon.lpstrFilter =TEXT("Text Files (*.txt)\0*.txt\0All Files (*.*)\0*.*\0");
						fon.lpstrFile =szFileName;
						fon.nMaxFile = MAX_PATH;
						fon.Flags = OFN_EXPLORER | OFN_FILEMUSTEXIST | OFN_HIDEREADONLY;
						fon.lpstrDefExt =TEXT("txt");
						if(GetOpenFileName(&fon))
						{
							i=inserare_fisier(szFileName);
							if (i==1)
							{
								if(ifisier!=0)
								{
									StartCounter();
									for(int i=0;i<ifisier;i++)
									{
										NODE* temp1 = CREATE_BNODE(v[i]);
										root1 = INSERT_BHEAP(root1, temp1);
									}
									timp_inserare=GetCounter();
									
									char c[300];
									sprintf(c,"%d",ifisier);
									strcat(c, " elements were inserted");
									 MessageBox(hwnd, c,"Attention",MB_OK|MB_ICONEXCLAMATION);
									 NODE*aux=root1;
									 StartCounter();
									 NODE* nnn=MIN_BHEAP(aux);
									 timp_cautare_min=GetCounter();
									 nod_minim=nnn->info;

									 display(root1);
								}
								else
									MessageBox(NULL,"The file is empty orit doesnt contain ONLY integer positive values","New File", MB_OK | MB_ICONINFORMATION);
							}
							else
								MessageBox(hwnd,"A FOST O PROBLEMA LA DESCHIDEREA FISIERULUI","Eroare",MB_OK);
						}
						
				}
				break;
				case IDC_BUTTON2:
				{
					display_grafic_timp(timp_inserare, timp_cautare_min, nod_minim);
				}
				break;
				case IDC_ADD:
				{

					BOOL bSuccess;
					int value = GetDlgItemInt(hwnd, IDC_TEXT, &bSuccess, FALSE);
					if(bSuccess) 
					{
						NODE* temp = CREATE_BNODE(value);
						root[curr_heap] = INSERT_BHEAP(root[curr_heap], temp);

						display(root[curr_heap]);


					
					}
					else 
					{
						MessageBox(hwnd, "Numar Invalid !", "Warning", MB_OK);
					}

				}
				break;
				case IDC_DELMIN:
					{
						NODE* aux=root[curr_heap];
						EXTRACT_MIN(aux);
						SendDlgItemMessage(hwnd, IDC_LIST, LB_RESETCONTENT, 0, 0);

						display(root[curr_heap]);
					}
					break;
				case IDC_DEGKEY:
					{
						BOOL bSuccess;
						int value1 = GetDlgItemInt(hwnd, IDC_TEXT3, &bSuccess, FALSE);
						if (!bSuccess)
						{
							MessageBox(hwnd, "Numar Invalid !", "Warning", MB_OK);
							break;
						}
						int value2 = GetDlgItemInt(hwnd, IDC_TEXT4, &bSuccess, FALSE);
						if (!bSuccess)
						{
							MessageBox(hwnd, "Numar Invalid !", "Warning", MB_OK);
							break;
						}
						DECREASE_KEY(root[curr_heap],value1,value2);
						SendDlgItemMessage(hwnd, IDC_LIST, LB_RESETCONTENT, 0, 0);

						display(root[curr_heap]);

					}
					break;
				case IDC_FIND:
					{
						double time;
						SendDlgItemMessage(hwnd, IDC_LIST, LB_RESETCONTENT, 0, 0);
						
						NODE *aux=root[curr_heap];
						if(aux)
						{
						StartCounter();
						NODE* nn=MIN_BHEAP(aux);
						time=GetCounter();
						if (nn)
						{
							char s[1100];
							sprintf(s,"Nodul nimim are valoarea: %d\nTipul de cautare %d milisecunde",nn->info,time);
							MessageBox(hwnd,s,"TIME",MB_OK);
							}
							else
							{
								char s[50];
								sprintf(s,"Eroare");
								MessageBox(hwnd,s,"TIME",MB_OK);
							}
						}

					}
					break;

				case IDC_UNION:
					{
						BOOL bSuccess;
						int value = GetDlgItemInt(hwnd, IDC_TEXT5, &bSuccess, FALSE);
						SendDlgItemMessage(hwnd, IDC_LIST, LB_RESETCONTENT, 0, 0);

						MERGE_BHEAP(root[curr_heap],root[value]);
						SendDlgItemMessage(hwnd, IDC_LIST, LB_RESETCONTENT, 0, 0);
						
						display(root[value]);

					}
					break;
				case IDC_DEL:
					{
					//	MessageBox(hwnd," aicii !", "Warning", MB_OK);
						for (int i=curr_heap; i<nr_root; i++)
							root[i]=root[i+1];
						nr_root--;
						curr_heap=0;
						SetDlgItemInt(hwnd, IDC_SHOWCOUNT2 , curr_heap,FALSE);
					SetDlgItemInt(hwnd, IDC_SHOWCOUNT , nr_root,FALSE);
					}
					break;
				case IDC_UNION2:
					{
						BOOL bSuccess;
						curr_heap = GetDlgItemInt(hwnd, IDC_TEXT2, &bSuccess, FALSE);
						if(curr_heap>nr_root)
							curr_heap=nr_root;

						if (!bSuccess)
						{
							MessageBox(hwnd, "Numar Invalid !", "Warning", MB_OK);
							break;
						}
						if (!bSuccess)
						{
							MessageBox(hwnd, "Numar Invalid !", "Warning", MB_OK);
							break;
						}
						SetDlgItemInt(hwnd, IDC_SHOWCOUNT2 , curr_heap,FALSE);
						SendDlgItemMessage(hwnd, IDC_LIST, LB_RESETCONTENT, 0, 0);
						
						display(root[curr_heap]);
						
					}
					break;

				case IDC_NEW:
				root[nr_root] = CREATE_BHEAP();
				SendDlgItemMessage(hwnd, IDC_LIST, LB_RESETCONTENT, 0, 0);
					curr_heap=nr_root;
					nr_root++;
					SetDlgItemInt(hwnd, IDC_SHOWCOUNT2 , curr_heap,FALSE);
					SetDlgItemInt(hwnd, IDC_SHOWCOUNT , nr_root,FALSE);
					display(root[curr_heap]);
					break;
				
					
				
			}
		break;
		
		case WM_CLOSE:
			EndDialog(hwnd, 0);
		break;
		default:
			return FALSE;
	}
	return TRUE;
}

LRESULT CALLBACK WndProc(HWND hwnd2, UINT msg, WPARAM wParam, LPARAM lParam )
{
	//DialogBox(NULL, MAKEINTRESOURCE(IDD_MAIN), NULL, DlgProc);
	int wmId, wmEvent;
	PAINTSTRUCT Ps;

    switch(msg)
    {		
		case WM_PAINT:
			hdc=BeginPaint(hwnd2, &Ps);

			EndPaint(hwnd2, &Ps);
			break;

		case WM_COMMAND:
			wmId    = LOWORD(wParam);
			wmEvent = HIWORD(wParam);
			switch (wmId)
			{
				case ID_ACTION:
					DialogBox(hInst, MAKEINTRESOURCE(IDD_MAIN), NULL, DlgProc);
				break;
			}
			break;
        case WM_CLOSE:
            DestroyWindow(hwnd2);
        break;
        case WM_DESTROY:
            PostQuitMessage(0);
        break;
		

        default:
            return DefWindowProc(hwnd2, msg, wParam, lParam);
    }
    return 0;
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
    LPSTR lpCmdLine, int nCmdShow)
{
    WNDCLASSEX wc;
    MSG Msg;

    //Step 1: Registering the Window Class
      wc.cbSize        = sizeof(WNDCLASSEX);
    wc.style         = CS_BYTEALIGNWINDOW|CS_HREDRAW|CS_VREDRAW|CS_DBLCLKS;
    wc.lpfnWndProc   = WndProc;
    wc.cbClsExtra    = 0;
    wc.cbWndExtra    = 0;
    wc.hInstance     = hInstance;
    wc.hIcon         = LoadIcon(NULL, IDI_APPLICATION);
    wc.hCursor       = LoadCursor(NULL, IDC_ARROW);
    wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
    wc.lpszMenuName  =MAKEINTRESOURCE(IDR_MENU1);
   wc.lpszClassName ="myWindowClass";
    wc.hIconSm       = LoadIcon(NULL, IDI_APPLICATION);

    if(!RegisterClassEx(&wc))
    {
        MessageBox(NULL, "Window Registration Failed!", "Error!",
            MB_ICONEXCLAMATION | MB_OK);
        return 0;
    }

    // Step 2: Creating the Window
  hwnd = CreateWindowEx( WS_EX_CLIENTEDGE,"myWindowClass","Binomial",WS_OVERLAPPEDWINDOW,CW_USEDEFAULT, CW_USEDEFAULT, 840, 520,NULL, NULL, hInstance, NULL);

    if(hwnd == NULL)
    {
        MessageBox(NULL, "Window Creation Failed!", "Error!",
            MB_ICONEXCLAMATION | MB_OK);
        return 0;
    }

    ShowWindow(hwnd,  SW_MAXIMIZE);
    UpdateWindow(hwnd);

    // Step 3: The Message Loop
    while(GetMessage(&Msg, NULL, 0, 0) > 0)
    {
        TranslateMessage(&Msg);
        DispatchMessage(&Msg);
    }
    return Msg.wParam;
}

